home *** CD-ROM | disk | FTP | other *** search
/ Acorn User: China / Acorn User China CD-ROM (UK) (Disc A) / Acorn User China CD-ROM (UK) (Disc A).bin / ARMCLUB / DRUCK / SPRITE_TOOLS.ARC / c / process < prev    next >
Encoding:
Text File  |  1999-01-10  |  27.3 KB  |  980 lines

  1. /************************************************************************
  2.  *                                                                      *
  3.  * process.c                                                            *
  4.  * =========                                                            *
  5.  *                                                                      *
  6.  * RISCOS sprite style bitmap processing library                        *
  7.  * Uses spr_info generic bitmap interface from sprite.c library         *
  8.  *                                                                      *
  9.  * Supports scaling, depth (colour) expansion/reduction                 *
  10.  * with limited image processing features.                              *
  11.  * Uses Floyd-Steinburg Integer (FSI) error distrubution dithering      *
  12.  *                                                                      *
  13.  * Version 0.01 (18-Jan-1993)                                           *
  14.  *         0.02 (24-Feb-1993)                                           *
  15.  *         0.03 (15-Mar-1993)                                           *
  16.  *         0.04 (28-Apr-1993)                                           *
  17.  *         0.05 (10-May-1993) Split from spr_fsi.c                      *
  18.  *         0.06 (16-Jun-1993)                                           *
  19.  *         0.07 (01-Sep-1993)                                           *
  20.  *         0.08 (09-Sep-1993) closest_rgb() optimizations added         *
  21.  *         0.09 (13-Sep-1993)                                           *
  22.  *         0.10 (13-Oct-1993)                                           *
  23.  *         1.00 (13-Jan-1994)                                           *
  24.  *         1.10 (20-Apr-1994) filters added                *
  25.  *         1.15 (05-May-1994) closest_rgb moved to colours.c        *
  26.  *         1.22 (11-May-1994) pix_sum interpolation addded        *
  27.  *         1.23 (06-Apr-1998) heap problem fix for win32 aswell        *
  28.  *         1.30 (06-Apr-1998) cropping added                    *
  29.  *                                                                      *
  30.  * (C) 1993-1998 DEEJ Technology PLC                                    *
  31.  *                                                                      *
  32.  ************************************************************************/
  33.  
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. #include <string.h>
  37. #include <math.h>
  38. #include "sprite.h"
  39. #include "colours.h"
  40. #include "palette.h"
  41. #include "process.h"
  42.  
  43. /****************************************************************************/
  44.  
  45. /*
  46.  * return intensity of RGB value
  47.  * to 16 bit, using fixed coding
  48.  */
  49.  
  50. uint intensity(uint rgb)
  51. {
  52.         return( ( ((rgb >> 8)  & 0xFF) * RED_WEIGHT   +
  53.                   ((rgb >> 16) & 0xFF) * GREEN_WEIGHT +
  54.                   ((rgb >> 24) )       * BLUE_WEIGHT ) );
  55. }
  56.  
  57. /*
  58.  * check for any excess colour components
  59.  * (<0 or >255) and calculate an excess intensity
  60.  * to be added to to all three components
  61.  */
  62.  
  63. void excess_rgb(pix_str *rgb)
  64. {
  65.         int excess = 0;
  66.  
  67.         if(rgb->red < 0)
  68.         {
  69.                 excess   = rgb->red * RED_WEIGHT;
  70.                 rgb->red = 0;
  71.         }
  72.         if(rgb->red > 255)
  73.         {
  74.                 excess   = (rgb->red - 255) * RED_WEIGHT;
  75.                 rgb->red = 255;
  76.         }
  77.         if(rgb->green < 0)
  78.         {
  79.                 excess    += rgb->green * GREEN_WEIGHT;
  80.                 rgb->green = 0;
  81.         }
  82.         if(rgb->green > 255)
  83.         {
  84.                 excess    += (rgb->green - 255) * GREEN_WEIGHT;
  85.                 rgb->green = 255;
  86.         }
  87.         if(rgb->blue < 0)
  88.         {
  89.                 excess   += rgb->blue  * BLUE_WEIGHT;
  90.                 rgb->blue = 0;
  91.         }
  92.         if(rgb->blue > 255)
  93.         {
  94.                 excess   += (rgb->blue - 255) * BLUE_WEIGHT;
  95.                 rgb->blue = 255;
  96.         }
  97.  
  98.         if(excess != 0)
  99.         {
  100.                 rgb->red   += (excess >> 16);
  101.                 rgb->green += (excess >> 16);
  102.                 rgb->blue  += (excess >> 16);
  103.         }
  104. }
  105.  
  106. /*
  107.  * Invert a sprite
  108.  * using palette translation if possible
  109.  */
  110.  
  111. void invert(spr_info_str *s)
  112. {
  113.         int x,y,x1,y1;
  114.         uint mask;
  115.  
  116.         if(s->has_palette)
  117.         {
  118.                 x1   = s->cols;
  119.                 y1   = 1;
  120.                 mask = 0xFFFFFF00;
  121.         }
  122.         else
  123.         {
  124.                 x1   = s->X;
  125.                 y1   = s->Y;
  126.  
  127.                 switch(s->bpp)
  128.                 {
  129.                         case  8: mask = 0x000000FF; break;
  130.                         case 15: mask = 0x00007FFF; break;
  131.                         case 24: mask = 0xFFFFFF00; break;
  132.                         default: break;
  133.                 }
  134.         }
  135.  
  136.     progress_start("Inverting   :");
  137.  
  138.         for(y=0; y<y1; y++)
  139.     {
  140.             for(x=0; x<x1; x++)
  141.             {
  142.                 if(s->has_palette)
  143.                 {
  144.                         s->palette[x] = (~s->palette[x]) & mask;
  145.                     progress(x, x1);
  146.                 }
  147.                 else
  148.                 {
  149.                         s->write_pixel_val(s, x, y,
  150.                                            ~s->read_pixel_val(s,x,y) & mask);
  151.                 }
  152.         }
  153.             if(!s->has_palette)
  154.                 progress(y, y1);
  155.         }
  156.  
  157.     progress_finish();
  158. }
  159.  
  160. /*
  161.  * Expand dynamic range of a sprite
  162.  * using palette translation if possible
  163.  */
  164.  
  165. void expand(spr_info_str *s)
  166. {
  167.         int   i,x,y,x1,y1;
  168.         uint  value,min,max;
  169.         uint  r,g,b;
  170.         uchar table[256];
  171.  
  172.         if(s->has_palette)
  173.         {
  174.                 x1 = s->cols;
  175.                 y1 = 1;
  176.         }
  177.         else
  178.         {
  179.                 x1 = s->X;
  180.                 y1 = s->Y;
  181.         }
  182.  
  183.         /* find min and max values */
  184.  
  185.         min = 255;
  186.         max = 0;
  187.  
  188.     progress_start("Find limits :");
  189.  
  190.         for(y=0; y<y1; y++)
  191.     {
  192.             for(x=0; x<x1; x++)
  193.             {
  194.                 if(s->has_palette)
  195.         {
  196.                         value = s->palette[x];
  197.                     progress(x, x1);
  198.         }
  199.                 else
  200.         {
  201.                         value = s->read_pixel_val(s,x,y);
  202.         }
  203.  
  204.                 SPLIT_RGB(value)
  205.  
  206.                 if(r < min) min = r;
  207.                 if(g < min) min = g;
  208.                 if(b < min) min = b;
  209.                 if(r > max) max = r;
  210.                 if(g > max) max = g;
  211.                 if(b > max) max = b;
  212.         }
  213.  
  214.             if(!s->has_palette)
  215.                 progress(y, y1);
  216.         }
  217.  
  218.     progress_finish();
  219.     progress_start("Expanding   :");
  220.  
  221.         for(i=0; i<256; i++)
  222.         {
  223.                 table[i] = ((i-min)*255)/(max-min);
  224.         }
  225.  
  226.         table_lookup(s, table);
  227.  
  228.     progress_finish();
  229. }
  230.  
  231. /*
  232.  * correct gamma of a sprite
  233.  * using palette translation if possible
  234.  */
  235.  
  236. void gamma_cr(spr_info_str *s, float gamma)
  237. {
  238.         int  i;
  239.         uchar table[256];
  240.  
  241.     progress_start("Gamma corrct:");
  242.  
  243.         for(i=0; i<256; i++)
  244.         {
  245.             table[i] = (char)(pow((double)i/255.0, 1.0/(double)gamma)*255.0);
  246.         }
  247.         table_lookup(s, table);
  248.  
  249.     progress_finish();
  250. }
  251.  
  252. /*
  253.  * perform table lookup on on r,g,b components
  254.  * on a sprites palette, or pixels if paletteless
  255.  */
  256.  
  257. void table_lookup(spr_info_str *s, uchar *table)
  258. {
  259.         int x,y,x1,y1;
  260.         uint value, r,g,b;
  261.         pix_str rgb;
  262.  
  263.         if(s->has_palette)
  264.         {
  265.                 x1 = s->cols;
  266.                 y1 = 1;
  267.         }
  268.         else
  269.         {
  270.                 x1 = s->X;
  271.                 y1 = s->Y;
  272.         }
  273.  
  274.         for(y=0; y<y1; y++)
  275.     {
  276.             for(x=0; x<x1; x++)
  277.             {
  278.                 if(s->has_palette)
  279.         {
  280.                         value = s->palette[x];
  281.                     progress(x, x1);
  282.         }
  283.                 else
  284.         {
  285.                         value = s->read_pixel_val(s,x,y);
  286.         }
  287.  
  288.                 SPLIT_RGB(value);
  289.  
  290.                 rgb.red   = table[r];
  291.                 rgb.green = table[g];
  292.                 rgb.blue  = table[b];
  293.  
  294.                 if(s->has_palette)
  295.         {
  296.             rgb.value     = (rgb.blue  << 24) |
  297.                         (rgb.green << 16) |
  298.                         (rgb.red   <<  8);
  299.                         s->palette[x] =  rgb.value;
  300.         }
  301.                 else
  302.         {
  303.                         s->write_pixel_val(s,x,y,s->closest_rgb(s,&rgb)->value);
  304.         }
  305.         }
  306.             if(!s->has_palette)
  307.                 progress(y, y1);
  308.         }
  309. }
  310.  
  311. /*
  312.  * Apply a filter to a sprite
  313.  * should really only be used on 15/24 bpp
  314.  * as no error diffusion will be done on
  315.  * closest values used on substution
  316.  */
  317.  
  318. void filter(spr_info_str *s, filter_str *f)
  319. {
  320.         int i, x,y, x2,y2;
  321.     int     sum[3],mul;
  322.     uint    *buffer[3];
  323.         uint    val;
  324.     pix_str pix;
  325.  
  326.     /* get a three line buffer */
  327.  
  328.     if((buffer[0] = malloc(s->X*4))==0 ||
  329.        (buffer[1] = malloc(s->X*4))==0 ||
  330.        (buffer[2] = malloc(s->X*4))==0)
  331.     {
  332.                 fprintf(stderr,"Error: Failed to allocate filter buffer");
  333.                 fprintf(stderr,"- unable to continue\n");
  334.                 exit(1);
  335.         }
  336.  
  337.     progress_start("Filtering   :");
  338.  
  339.     /* read first three lines into buffer */
  340.  
  341.     for(y=0; y<3; y++)
  342.     for(x=0; x<s->X; x++)
  343.     {
  344.         buffer[y][x] = s->read_pixel_rgb(s, x, y);
  345.     }
  346.  
  347.         for(y=1; y<s->Y-1; y++)
  348.     {
  349.             for(x=1; x<s->X-1; x++)
  350.             {
  351.         /* sum weighted pixel component values in 3x3 matrix */
  352.  
  353.         sum[0] = sum[1] = sum[2] = 0;
  354.  
  355.         for(y2=0; y2<3; y2++)
  356.         for(x2=0; x2<3; x2++)
  357.         {
  358.             if((mul = f->matrix[y2][x2])!=0)
  359.             {
  360.                 val     = buffer[y2][x+x2-1];
  361.                 sum[0] += (((val>>8)  & 0xFF) * mul);
  362.                 sum[1] += (((val>>16) & 0xFF) * mul);
  363.                 sum[2] += (((val>>24) & 0xFF) * mul);
  364.             }
  365.         }
  366.  
  367.         if(f->diff != 0)
  368.             val    = s->read_pixel_rgb(s, x, y);
  369.  
  370.         /* filter each component seperately */
  371.  
  372.         for(i=0; i<3; i++)
  373.         {
  374.             /* multiply, divide and add constant to sum */
  375.  
  376.             if(f->mul != 1) sum[i] *= f->mul;
  377.             if(f->div != 1) sum[i] /= f->div;
  378.                     sum[i] += f->add;
  379.  
  380.             /* check for differencing (noise) filter */
  381.  
  382.             if(f->diff != 0)
  383.             {
  384.                 int diff = ((val >> ((i+1)*8)) & 0xFF) - sum[i];
  385.  
  386.                 if(diff<0) diff = -diff;
  387.  
  388.                 /* use centre value if diff in range */
  389.  
  390.                 if(diff <= f->diff)
  391.                     sum[i] = (val >> ((i+1)*8)) & 0xFF;
  392.             }
  393.             RANGE_RGB(sum[i]);
  394.         }
  395.  
  396.         /* write new value to centre pixel */
  397.  
  398.         pix.red   = sum[0];
  399.         pix.green = sum[1];
  400.         pix.blue  = sum[2];
  401.         s->write_pixel_val(s, x,y, s->closest_rgb(s, &pix)->value);
  402.         }
  403.  
  404.         /* copy lines up buffer and read next */
  405.  
  406.         memcpy(buffer[0], buffer[1], s->X*4);
  407.         memcpy(buffer[1], buffer[2], s->X*4);
  408.         for(x=0; x<s->X; x++)
  409.         {
  410.         buffer[2][x] = s->read_pixel_rgb(s, x, y+1);
  411.         }
  412.             progress(y, s->Y-2);
  413.         }
  414.  
  415.     progress_finish();
  416.  
  417.     free((void*)buffer[0]);
  418.     free((void*)buffer[1]);
  419.     free((void*)buffer[2]);
  420. }
  421.  
  422. /*
  423.  * diffuses fraction of RGB error to pixel
  424.  * parameters are the address of an R,G,B integer triplet
  425.  * the r,g,b error values as integers and a 16 bit
  426.  * fixed point fraction
  427.  */
  428.  
  429. void err_diff(pix_str *pixel, pix_str *err, int factor)
  430. {
  431.         pixel->red   += (err->red   * factor);
  432.         pixel->green += (err->green * factor);
  433.         pixel->blue  += (err->blue  * factor);
  434. }
  435.  
  436. /*
  437.  * sums pixels along a row, used by pix_sum
  438.  * averages pixels for contraction and
  439.  * interploates for expansion
  440.  * x1i,x1f = start for sum, pixel centre for interpolation
  441.  * x2i,x2f = end for sum, unused for interploation
  442.  */
  443.  
  444. static void pix_sum_row(spr_info_str *in, pix_str *sumX,
  445.                         int x1i, int x1f,
  446.                         int x2i, int x2f,
  447.                         int y, int div,
  448.             BOOL interpX)
  449. {
  450.         REGISTER int  x;
  451.         REGISTER uint rgb;
  452.     REGISTER int  r,g,b;
  453.  
  454.     if(interpX)
  455.     {
  456.         /* interploate between pixels centers */
  457.  
  458.             rgb         = in->read_pixel_rgb(in, x1i, y);
  459.         sumX->red   = (rgb >>  8) & 0xFF;
  460.         sumX->green = (rgb >> 16) & 0xFF;
  461.         sumX->blue  = (rgb >> 24) & 0xFF;
  462.  
  463.         if(x1f<0x8000 && x1i>0)
  464.         {
  465.             /* left of x center so add proportion */
  466.                         /* of previous pixel (0 to 0.5)       */
  467.  
  468.                 rgb = in->read_pixel_rgb(in, x1i-1, y);
  469.             SPLIT_RGB(rgb);
  470.  
  471.             sumX->red   += ((r - sumX->red  )*(0x8000-x1f)) >> 16;
  472.             sumX->green += ((g - sumX->green)*(0x8000-x1f)) >> 16;
  473.             sumX->blue  += ((b - sumX->blue )*(0x8000-x1f)) >> 16;
  474.         }
  475.         else if(x1f>0x8000 && x1i<(in->X-1))
  476.         {
  477.             /* right of x center so add proportion */
  478.                         /* of next pixel (0 to 0.5)            */
  479.  
  480.                 rgb = in->read_pixel_rgb(in, x1i+1, y);
  481.             SPLIT_RGB(rgb);
  482.  
  483.             sumX->red   += ((r - sumX->red  )*(x1f-0x8000)) >> 16;
  484.             sumX->green += ((g - sumX->green)*(x1f-0x8000)) >> 16;
  485.             sumX->blue  += ((b - sumX->blue )*(x1f-0x8000)) >> 16;
  486.         }
  487.     }
  488.     else
  489.     {
  490.             sumX->red = sumX->green = sumX->blue = 0;
  491.  
  492.             /* read first pixel */
  493.  
  494.             rgb = in->read_pixel_rgb(in, x1i, y);
  495.             SPLIT_RGB(rgb);
  496.  
  497.             /* if start and end in same pixel, average is pixel value */
  498.  
  499.             if(x1i==x2i)
  500.             {
  501.                     sumX->red   = r;
  502.                     sumX->green = g;
  503.                     sumX->blue  = b;
  504.             }
  505.             else
  506.             {
  507.                     /* sum fraction of first pixel if any */
  508.  
  509.                     if(x1f > 0)
  510.                     {
  511.                             sumX->red   = r * (0x10000-x1f);
  512.                             sumX->green = g * (0x10000-x1f);
  513.                             sumX->blue  = b * (0x10000-x1f);
  514.                     }
  515.                     else
  516.                     {
  517.                             sumX->red   = (r<<16);
  518.                             sumX->green = (g<<16);
  519.                             sumX->blue  = (b<<16);
  520.                     }
  521.  
  522.                     /* sum whole pixels between x1+1 & x2 */
  523.  
  524.                     if((x1i+1) < x2i)
  525.                     {
  526.                         for(x=x1i+1; x<x2i; x++)
  527.                         {
  528.                             rgb = in->read_pixel_rgb(in, x, y);
  529.                             SPLIT_RGB(rgb);
  530.  
  531.                             sumX->red   += (r<<16);
  532.                             sumX->green += (g<<16);
  533.                             sumX->blue  += (b<<16);
  534.                         }
  535.                     }
  536.  
  537.                     /* sum fractaction of last pixel if any */
  538.  
  539.                     if(x2f > 0)
  540.                     {
  541.                             rgb = in->read_pixel_rgb(in, x2i, y);
  542.                             SPLIT_RGB(rgb);
  543.  
  544.                             sumX->red   += r * x2f;
  545.                             sumX->green += g * x2f;
  546.                             sumX->blue  += b * x2f;
  547.                     }
  548.  
  549.                     /* average over number of whole & part pixels */
  550.  
  551.                     sumX->red   = sumX->red   / div;
  552.                     sumX->green = sumX->green / div;
  553.                     sumX->blue  = sumX->blue  / div;
  554.             }
  555.     }
  556. }
  557.  
  558. /*
  559.  * Averages an area of pixel fragments for contraction
  560.  * and interpolates between pixel centers for expansion
  561.  *
  562.  * Parameters are 16 bit fixed point positions
  563.  * of pixel area to be summed in source bitmaps
  564.  * x1,y1 = top left (inclusive)
  565.  * x2,y2 = bottom right (exclusive)
  566.  * (top left = 0,0)
  567.  *
  568.  * NOTE: fixed point fails if summing > 128 pixels in either direction
  569.  *       fractions are round fractions of pixels to prevent stepping
  570.  *       inaccuracies causing small fractions of pixels
  571.  *       to be summed, <1/256 can be ignored with no effect
  572.  */
  573.  
  574. pix_str pix_sum(spr_info_str *in, int x1, int y1, int x2, int y2)
  575. {
  576.         REGISTER int y;
  577.         REGISTER int x1i,y1i, x1f,y1f;
  578.         REGISTER int x2i,y2i, x2f,y2f;
  579.              int div;
  580.         pix_str  sumX, sumY;
  581.     BOOL     interpX = (x2-x1) < 0x10000;    /* interplate if expanding */
  582.         BOOL     interpY = (y2-y1) < 0x10000;    /* average if contracting  */
  583.  
  584.     if(interpX)
  585.     {
  586.         /* find pixel centre for interpolation */
  587.  
  588.             x1  = (x1+x2)>>1;
  589.             x1i = (x1 >> 16);
  590.             x1f = (x1 & 0xFFFF);
  591.  
  592.         /* round pixel fractions */
  593.  
  594.             if(x1f < 256) x1f=0;   if(x1f > 65280) { x1f=0; x1i++; }
  595.  
  596.             /* ensure original coords match new values */
  597.  
  598.             x1 = (x1i << 16)+x1f;
  599.     }
  600.     else
  601.     {
  602.         /* make integer and fractional parts for start/end */
  603.  
  604.             x1i = (x1 >> 16);
  605.             x1f = (x1 & 0xFFFF);
  606.             x2i = (x2 >> 16);
  607.             x2f = (x2 & 0xFFFF);
  608.  
  609.         /* round pixel fractions */
  610.  
  611.             if(x1f < 256) x1f=0;    if(x1f > 65280) { x1f=0; x1i++; }
  612.             if(x2f < 256) x2f=0;    if(x2f > 65280) { x2f=0; x2i++; }
  613.  
  614.             /* ensure original coords match new values */
  615.  
  616.             x1 = (x1i << 16)+x1f;
  617.             x2 = (x2i << 16)+x2f;
  618.  
  619.         /* pixel row sum divisor */
  620.  
  621.             div = (x2-x1);
  622.     }
  623.  
  624.     if(interpY)
  625.     {
  626.         /*
  627.          * interpolate between (sum/interpolation) of pixel rows
  628.          */
  629.             pix_str sumYn;
  630.  
  631.         /* find pixel centre for interpolation */
  632.  
  633.         y1  = (y1+y2)>>1;
  634.         y1i = (y1 >> 16);
  635.         y1f = (y1 & 0xFFFF);
  636.  
  637.         /* round pixel fractions */
  638.  
  639.             if(y1f < 256) y1f=0;    if(y1f > 65280) { y1f=0; y1i++; }
  640.  
  641.             /* ensure original coords match new values */
  642.  
  643.             y1 = (y1i << 16)+y1f;
  644.  
  645.         /* interpolate between centers of pixel rows if expanding */
  646.  
  647.             pix_sum_row(in, &sumY, x1i,x1f, x2i,x2f, y1i,div, interpX);
  648.  
  649.         if(y1f<0x08000 && y1i>0)
  650.         {
  651.             /* above y1 center so add proportion */
  652.                 /* of previous row (0 to 0.5)        */
  653.  
  654.             pix_sum_row(in, &sumYn, x1i,x1f,
  655.                         x2i,x2f, y1i-1, div, interpX);
  656.  
  657.             sumY.red   += ((sumYn.red   - sumY.red)   *
  658.                     (0x8000-y1f)) >> 16;
  659.             sumY.green += ((sumYn.green - sumY.green) *
  660.                     (0x8000-y1f)) >> 16;
  661.             sumY.blue  += ((sumYn.blue  - sumY.blue)  *
  662.                     (0x8000-y1f)) >> 16;
  663.         }
  664.         else if(y1f>0x08000 && y1i>(in->Y-1))
  665.         {
  666.             /* below y1 center so add proportion */
  667.                 /* of next row (0 to 0.5)            */
  668.  
  669.             pix_sum_row(in, &sumYn, x1i,x1f,
  670.                         x2i,x2f, y1i+1, div, interpX);
  671.  
  672.             sumY.red   += ((sumYn.red   - sumY.red)   *
  673.                     (y1f-0x8000)) >> 16;
  674.             sumY.green += ((sumYn.green - sumY.green) *
  675.                     (y1f-0x8000)) >> 16;
  676.             sumY.blue  += ((sumYn.blue  - sumY.blue)  *
  677.                     (y1f-0x8000)) >> 16;
  678.         }
  679.         return(sumY);
  680.     }
  681.  
  682.     /*
  683.          * sum whole and partial pixel rows
  684.      */
  685.  
  686.     sumY.red = sumY.green = sumY.blue = 0;
  687.  
  688.     /* make integer and fractional parts for start/end */
  689.  
  690.         y1i = (y1 >> 16);
  691.         y1f = (y1 & 0xFFFF);
  692.         y2i = (y2 >> 16);
  693.         y2f = (y2 & 0xFFFF);
  694.  
  695.     /* round pixel fractions */
  696.  
  697.         if(y1f < 256) y1f=0;    if(y1f > 65280) { y1f=0; y1i++; }
  698.         if(y2f < 256) y2f=0;    if(y2f > 65280) { y2f=0; y2i++; }
  699.  
  700.         /* ensure original coords match new values */
  701.  
  702.         y1 = (y1i << 16)+y1f;
  703.         y2 = (y2i << 16)+y2f;
  704.  
  705.         /* correct looping for whole last pixel row */
  706.  
  707.         if(y2f==0) y2i--;
  708.  
  709.         for(y=y1i; y<=y2i; y++)
  710.         {
  711.         /* sum or interpolate along pixel row */
  712.  
  713.         pix_sum_row(in, &sumX, x1i,x1f, x2i,x2f, y,div, interpX);
  714.  
  715.                 /* sum fraction of pixel row if not whole pixel high */
  716.  
  717.                 if((y==y1i) && (y!=y2i) && (y1f>0))
  718.                 {
  719.                         sumY.red   = sumX.red   * (0x10000-y1f);
  720.                         sumY.green = sumX.green * (0x10000-y1f);
  721.                         sumY.blue  = sumX.blue  * (0x10000-y1f);
  722.                 }
  723.                 else
  724.                 {
  725.                         /* sum faction of last pixel row if not whole */
  726.  
  727.                         if((y!=y1i) && (y==y2i) && (y2f>0))
  728.                         {
  729.                                 sumY.red   += sumX.red   * y2f;
  730.                                 sumY.green += sumX.green * y2f;
  731.                                 sumY.blue  += sumX.blue  * y2f;
  732.                         }
  733.                         else
  734.                         {
  735.                                 /* sum whole pixel rows */
  736.  
  737.                                 sumY.red   += (sumX.red   << 16);
  738.                                 sumY.green += (sumX.green << 16);
  739.                                 sumY.blue  += (sumX.blue  << 16);
  740.                         }
  741.                 }
  742.         }
  743.  
  744.         /*
  745.          * average over whole & part number of pixel rows
  746.          * fixed point is automatically converted to integer
  747.          * if start & end on the same row divid by 1
  748.          */
  749.  
  750.         div = (y2i==y1i) ? (1<<16) : (y2-y1);
  751.  
  752.         sumY.red   = sumY.red   / div;
  753.         sumY.green = sumY.green / div;
  754.         sumY.blue  = sumY.blue  / div;
  755.  
  756.         return(sumY);
  757. }
  758.  
  759. /*
  760.  * main sprite FSI processing routine
  761.  *
  762.  * if file valid write each processed line out immediately
  763.  * otherwise build destination sprite in memory
  764.  */
  765.  
  766. void process(process_str *p)
  767. {
  768.         REGISTER int inX, inY, outX, outY;
  769.         int Xinc, Yinc, Xdir, Ydir, x1, x2, y;
  770.         pix_str *line1, *line2;
  771.         pix_str sum, *new, err;
  772.  
  773.     /* get best function for finding closest RGB values */
  774.  
  775.     closest_rgb_func(p->in);
  776.  
  777.         /* do any preprocessing of the image */
  778.  
  779.     if(p->filter)      filter(p->in, &p->data.filter);
  780.         if(p->invert)      invert(p->in);
  781.         if(p->expand)      expand(p->in);
  782.         if(p->gamma)       gamma_cr(p->in,p->data.gamma);
  783.  
  784.         /* calculate optimized palette after preprocessing */
  785.  
  786.         if(p->palette_opt) optimize_palette(p->in, p->out);
  787.  
  788.     /* get best function for finding closest RGB values */
  789.  
  790.     closest_rgb_func(p->out);
  791.  
  792.     /* write sprite header to file if given */
  793.  
  794.     if(p->outf != 0) write_sprite_header(p->out, p->outf);
  795.  
  796.         /* allocate memory for two lines of the sprite 32+32+32 bpp (r,g,b) */
  797.  
  798.         if((line1=(pix_str*)malloc(p->out->X*sizeof(pix_str)))==0 ||
  799.            (line2=(pix_str*)malloc(p->out->X*sizeof(pix_str)))==0)
  800.         {
  801.                 /* should really free line1 if <>0, but exiting anyway */
  802.                 fprintf(stderr,"Error: Failed to allocate working buffer");
  803.                 fprintf(stderr,"- unable to continue\n");
  804.                 exit(1);
  805.         }
  806.         memset((void*)line1, 0, p->out->X*sizeof(pix_str));
  807.         memset((void*)line2, 0, p->out->X*sizeof(pix_str));
  808.  
  809.     progress_start("Processing  :");
  810.  
  811.         /* main Floyd Steinburg Integer code */
  812.  
  813.         /* calculate cropping of source image and adjust input sizes */
  814.         if(p->crop.right  == 0) p->crop.right  = p->in->X;
  815.         if(p->crop.bottom == 0) p->crop.bottom = p->in->Y;
  816.         inX = p->crop.right  - p->crop.left;
  817.         inY = p->crop.bottom - p->crop.top;
  818.  
  819.         Xdir = 1;                      /* X direction for zig-zag */
  820.         Ydir = 1;                      /* Y direction fixed (down)*/
  821.         Xinc = (inX<<16) / p->out->X;  /* 16.16 bit fixed point   */
  822.         Yinc = (inY<<16) / p->out->Y;  /* increment through input */
  823.         inY  = p->crop.top<<16;
  824.  
  825.         for(outY=0; outY<=p->out->Y-1; outY+=Ydir)
  826.         {
  827.                 /* X position is always top left of pixel regradless of dir */
  828.  
  829.                 if(Xdir==1)
  830.                 {
  831.                         x1  = 0;
  832.                         x2  = p->out->X;
  833.                         inX = p->crop.left<<16;
  834.                 }
  835.                 else
  836.                 {
  837.                         x1  = p->out->X-1;
  838.                         x2  = -1;
  839.                         inX = (p->crop.right<<16)+Xinc;
  840.                 }
  841.  
  842.                 for(outX=x1; outX!=x2; outX+=Xdir)
  843.                 {
  844.                         /* ensure that x1 is less than x2 and  */
  845.                         /* that y1 is less than y2 for pix_sum */
  846.  
  847.             if(p->nointerp)
  848.             {
  849.                 sum.value = p->in->read_pixel_rgb(p->in,
  850.                                                               inX>>16,
  851.                                                               inY>>16);
  852.                 sum.red   = (sum.value >>  8) & 0xFF;
  853.                 sum.green = (sum.value >> 16) & 0xFF;
  854.                 sum.blue  = (sum.value >> 24) & 0xFF;
  855.             }
  856.             else
  857.             {
  858.                             if(Xdir==1)
  859.                             {
  860.                                 sum = pix_sum(p->in, inX,      inY,
  861.                                                      inX+Xinc, inY+Yinc);
  862.                             }
  863.                             else
  864.                             {
  865.                                 sum = pix_sum(p->in, inX,      inY,
  866.                                                      inX-Xinc, inY+Yinc);
  867.                             }
  868.             }
  869.  
  870.                         if(!p->nodither)
  871.                         {
  872.                             /* add any error distributed to this pixel */
  873.  
  874.                             sum.red   += (line1[outX].red   >> 8);
  875.                             sum.green += (line1[outX].green >> 8);
  876.                             sum.blue  += (line1[outX].blue  >> 8);
  877.  
  878.                             excess_rgb(&sum);
  879.  
  880.                             new = p->out->closest_rgb(p->out, &sum);
  881.  
  882.                             line1[outX].value = new->value;
  883.  
  884.                             /* use full sum+line1 values for error calc */
  885.  
  886.                             err.red   = sum.red   - new->red;
  887.                             err.green = sum.green - new->green;
  888.                             err.blue  = sum.blue  - new->blue;
  889.  
  890.                             /* distribute error:    , pixel*1 , err*7/16, */
  891.                             /*              err*3/16, err*5/16, err*1/16, */
  892.  
  893.                             err_diff(&line1[outX], new, (16*0x100)/16);
  894.  
  895.                             /* speedup check for exact match */
  896.  
  897.                             if(err.red!=0 || err.green!=0 || err.blue!=0)
  898.                             {
  899.                                 if((Xdir == 1  && outX < (x2-1)) ||
  900.                                    (Xdir == -1 && outX > 0))
  901.                                 {
  902.                                     err_diff(&line1[outX+Xdir],
  903.                                              &err, (7*0x100)/16); /* 7/16 */
  904.                                 }
  905.                                 if(outY < (p->out->Y-1))
  906.                                 {
  907.                                     err_diff(&line2[outX],
  908.                                              &err, (5*0x100)/16); /* 5/16 */
  909.  
  910.                                     if((Xdir == 1  && outX < (x2-1)) ||
  911.                                        (Xdir == -1 && outX > 0))
  912.                                     {
  913.                                         err_diff(&line2[outX-Xdir],
  914.                                                  &err, (1*0x100)/16); /*1/16*/
  915.                                     }
  916.                                     if((Xdir == 1  && outX > 0) ||
  917.                                        (Xdir == -1 && outX < (x2-1)))
  918.                                     {
  919.                                         err_diff(&line2[outX+Xdir],
  920.                                                  &err, (3*0x100)/16); /*3/16*/
  921.                                     }
  922.                                 }
  923.                             }
  924.                         }
  925.                         else
  926.                         {
  927.                             /* no dither, so just find nearest colour */
  928.  
  929.                             new = p->out->closest_rgb(p->out, &sum);
  930.                             line1[outX].value = new->value;
  931.                         }
  932.                         inX += Xinc;
  933.                 }
  934.  
  935.                 Xdir = -Xdir;     /* reverse Xdir for zigzag */
  936.                 Xinc = -Xinc;
  937.                 inY += Yinc;
  938.  
  939.                 /*
  940.          * make one line of output sprite
  941.          * use y=0 if file is valid as only one line of data has been
  942.                  * allocated, otherwise place line in correct y position to
  943.                  * make whole sprite in memory
  944.          */
  945.  
  946.         if(p->outf==0)
  947.             y = outY;
  948.         else
  949.             y = 0;
  950.  
  951.                 for(outX=0; outX<p->out->X; outX++)
  952.                 {
  953.                         p->out->write_pixel_val(p->out, outX, y,
  954.                                                 line1[outX].value);
  955.                 }
  956.  
  957.                 /* write pixel line to file immediately if required */
  958.  
  959.         if(p->outf != 0)
  960.         {
  961.             fwrite(p->out->spr_data, p->out->line_size, 1, p->outf);
  962.         }
  963.  
  964.                 /* copy up second line of buffer, and clear */
  965.  
  966.                 memcpy(line1, line2, p->out->X*sizeof(pix_str));
  967.                 memset(line2, 0, p->out->X*sizeof(pix_str));
  968.  
  969.         progress(outY, p->out->Y);
  970.         }
  971.  
  972.     progress_finish();
  973.  
  974. /* #### run time heap problem under RISC OS and Win32 */
  975. #if!defined(RISCOS) && !defined(WIN32)
  976.         free((void*)line1);
  977.     free((void*)line2);
  978. #endif
  979. }
  980.